package com.example.springdatajpa.dao;

import com.example.springdatajpa.entity.Customer;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;

import java.util.List;

/**
 * @author wangning
 * @create 2021-03-06 16:18
 * @description
 */

/**
 * JpaRepository<实体类类型，实体类主键类型> ： 用来完成基本的 CRUD 操作
 * 为什么还要继承JpaSpecificationExecutor，肯定是这个接口里的更加好用
 * 例如JpaSpecificationExecutor中的count方法就可以根据条件查询记录数
 * 分页也可带条件
 * JpaSpecificationExecutor弥补了JpaRepository中不能带条件分页，count等问题
 */
public interface CustomerDao extends JpaRepository<Customer, Long>, JpaSpecificationExecutor<Customer> {

	List<Customer> findCustomerByCustIdGreaterThan(Long custId);

	/**
	 * JPQL查询
	 * 这种占位符是使用位置来传参数，还可以使用属性就行传参
	 * 以下两种方式都可以
	 *
	 * @param custId
	 * @param custLevel
	 * @return
	 */
	@Query("from Customer where custId>?1 and custLevel = ?2")
	List<Customer> testCustomer(Long custId, String custLevel);

	@Query("from Customer where custId>:id and custLevel = :level")
	List<Customer> testCustomer1(@Param("id") Long custId, @Param("level") String custLevel);

	/**
	 * 此处的条件不管有几个，@Param不能省略
	 *
	 * @param custId
	 * @return
	 */
	@Query("from Customer where custId>:custId")
	List<Customer> testCustomer2(@Param("custId") Long custId);

	@Query("from Customer where custId>?1 and custName like %?2%")
	List<Customer> testCustomer3(Long custId, String custName);

	@Query(value = "from Customer where custId>:id and custName like %:name%")
	List<Customer> testCustomer4(@Param("id") Long custId, @Param("name") String custName);

	/**
	 * 如果不休息JPQL，也可以写sql语句进行查询，只需要在@Query注解中添加nativeQuery = true
	 * 可以通过自定义的JPQL来进行DELETE 或者 UPDATE， 注意JQPL不能用于INSERT
	 * 在JQPL中进行DELETE或者UPDATE，需要@Modifying进行修饰
	 * DELETE或者UPDATE需要事务管理，此时需要定义service层，在service层上的方法上添加事务管理
	 * 因为默认情况下，SpringData每个方法上有事务，但都是一个只读事务，他们不能完成修改
	 */
	@Query(value = "select * from cst_customer", nativeQuery = true)
	List<Customer> chaxun();

	@Modifying
	@Query("update Customer set custName = ?1 where custId = ?2")
	int updateCustomer(String custName, Long custId);
}
